package com.example.tcp;

import androidx.appcompat.app.AppCompatActivity;

import android.graphics.Color;
import android.hardware.input.InputManager;
import android.os.Bundle;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.view.InputDevice;
import android.view.InputEvent;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.Locale;
import java.util.Timer;
import java.util.TimerTask;

public class MainActivity extends AppCompatActivity implements InputManager.InputDeviceListener{

    /* 控件定义 */
    private MyWebView mywebView;//视频流显示框
    private Button button_Connect;//连接按钮
    private Button button_Disconnect;//断开连接按钮
    private EditText editText_Host;//IP地址
    private EditText editText_Port;//端口号
    private TextView textView_State;//状态
    private TextView textView_Controller_State;
    /* 模式选择按钮 */
    private Button button_Mode_standing;//站立模式
    private Button button_Mode_telecontrol;//遥控模式
    private Button button_Mode_obstacle;//避障模式

    private Button button_light;//照明灯

    private Tcp_Client MyClient;
    private MyHandler myHandler;
    private MoveButton moveButton_left;
    private MoveButton moveButton_right;

    /* 变量 */
    private String host;//IP地址
    private int port;//端口号

    /* 硬件手柄数据 */
    private final String TAG = "game-controller";
    private int directionPressed = -1; // initialized to -1
    private int dpadAction = -1; // initialized to -1
    private float mPreviousLeftJoystickX;
    private float mPreviousLeftJoystickY;
    private float mPreviousRightJoystickX;
    private float mPreviousRightJoystickY;
    private static float leftJoystickX;
    private static float leftJoystickY;
    private static float rightJoystickX;
    private static float rightJoystickY;

    /* 手柄数据发送停止标志位 */
    private static boolean Joystick_send_left_flag = false;
    private static boolean Joystick_send_right_flag = false;

    /* 通讯信息 */
    public static final String Control_stop = "Z";
    public static final String Control_motor_forward = "A";
    public static final String Control_motor_back = "E";
    public static final String Control_motor_left = "G";
    public static final String Control_motor_right = "C";
    public static final String Control_steering_up = "I";
    public static final String Control_steering_down = "K";
    public static final String Control_steering_left = "J";
    public static final String Control_steering_right = "L";
    public static final String Control_mode_standing = "1";
    public static final String Control_mode_telecontrol = "2";
    public static final String Control_mode_obstacle = "3";
    public static final String Control_light_on = "4";
    public static final String Control_light_off = "5";


    /* 程序入口 */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        /* 去除手机顶部导航栏 */
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        /* 控件初始化 */
        mywebView = findViewById(R.id.WebView_jpeg_stream);
        button_Connect = findViewById(R.id.button_Connect);
        button_Disconnect = findViewById(R.id.button_Disconnect);
        editText_Host = findViewById(R.id.editText_Host);
        editText_Port = findViewById(R.id.editText_Port);
        textView_State = findViewById(R.id.textView_State);
        textView_Controller_State = findViewById(R.id.textView_Controller_State);
        button_Mode_standing = findViewById(R.id.button_Mode_standing);
        button_Mode_telecontrol = findViewById(R.id.button_Mode_telecontrol);
        button_Mode_obstacle = findViewById(R.id.button_Mode_obstacle);
        button_light = findViewById(R.id.button_light);
        moveButton_left = findViewById(R.id.Move_Button_left);
        moveButton_right = findViewById(R.id.Move_Button_right);
        myHandler = new MyHandler(Looper.myLooper(), textView_State, button_Mode_standing, button_Mode_telecontrol, button_Mode_obstacle, button_Disconnect, button_light, mywebView);
        moveButton_left.MoveButton_left_Init("left");
        moveButton_right.MoveButton_left_Init("w");

        updateGameControllerCount();

        /* 手柄左摇杆定时器发送数据 */
        new Timer().schedule(new TimerTask() {
            @Override
            public void run() {
                if(leftJoystickX > 0.1 || leftJoystickX < -0.1 || leftJoystickY > 0.1 || leftJoystickY < -0.1){
                    Log.v("leftJoystickX",""+leftJoystickX);
                    Log.v("leftJoystickY",""+leftJoystickY);
                    String buf = moveButton_left.Move_Button_steering_value(leftJoystickX*moveButton_left.Max_Distance,leftJoystickY*moveButton_left.Max_Distance);
                    if(button_Disconnect.getText().equals("断开") && button_Mode_telecontrol.getCurrentTextColor() == Color.rgb(0,255,0)) {
                        new Thread(new Runnable() {
                            @Override
                            public void run() {
                                MyClient.Send(buf+"\r\n");
                            }
                        }).start();
                    }
                    Joystick_send_left_flag = true;
                }
                else {
                    if(button_Disconnect.getText().equals("断开") && button_Mode_telecontrol.getCurrentTextColor() == Color.rgb(0,255,0) && Joystick_send_left_flag == true) {
                        new Thread(new Runnable() {
                            @Override
                            public void run() {
                                MyClient.Send("0\r\n");
                            }
                        }).start();
                    }
                    Joystick_send_left_flag = false;
                }
            }
        },2,10);

        /* 手柄右摇杆定时器发送数据 */
        new Timer().schedule(new TimerTask() {
            @Override
            public void run() {
                if(rightJoystickX > 0.1 || rightJoystickX < -0.1 || rightJoystickY > 0.1 || rightJoystickY < -0.1){
                    Log.v("rightJoystickX",""+rightJoystickX);
                    Log.v("rightJoystickY",""+rightJoystickY);
                    String buf = moveButton_right.Move_Button_motor_value(rightJoystickX*moveButton_right.Max_Distance,rightJoystickY*moveButton_right.Max_Distance);
                    if(button_Disconnect.getText().equals("断开") && button_Mode_telecontrol.getCurrentTextColor() == Color.rgb(0,255,0)) {
                        new Thread(new Runnable() {
                            @Override
                            public void run() {
                                MyClient.Send(buf+"\r\n");
                            }
                        }).start();
                    }
                    Joystick_send_right_flag = true;
                }
                else {
                    if(button_Disconnect.getText().equals("断开") && button_Mode_telecontrol.getCurrentTextColor() == Color.rgb(0,255,0) && Joystick_send_right_flag == true) {
                        new Thread(new Runnable() {
                            @Override
                            public void run() {
                                MyClient.Send("0\r\n");
                            }
                        }).start();
                    }
                    Joystick_send_right_flag = false;
                }
            }
        },2,10);

        /* 连接按钮 */
        button_Connect.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (button_Disconnect.getText().equals("未连接")) {
                    editText_Host.setCursorVisible(false);
                    editText_Port.setCursorVisible(false);
                    Joystick_send_left_flag = false;
                    Joystick_send_right_flag = false;

                    host = editText_Host.getText().toString();
                    port = Integer.parseInt(editText_Port.getText().toString());
                    Log.v("host", host);
                    Log.v("port", Integer.toString(port));
                    if (host != "" && port != 0) {
                        new Thread(new Runnable() {
                            @Override
                            public void run() {
                                MyClient = new Tcp_Client(host, port, myHandler);
                                MyClient.Connect();
                            }
                        }).start();
                    }
                } else {
                    textView_State.setText("请勿重复连接");
                    Log.v("button_Connect", "请勿重复连接");
                }
            }
        });

        /* 断开连接按钮 */
        button_Disconnect.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (button_Disconnect.getText().equals("断开")) {
                    button_Disconnect.setText("未连接");
                    /* 关闭mjpeg-stream拉流 */
                    Animation animation = new Rotate3dAnimation(mywebView.getWidth() / 2, mywebView.getHeight() / 2);
                    animation.setFillAfter(false);
                    mywebView.startAnimation(animation);
                    mywebView.stopLoading();//关闭WebView
                    mywebView.setVisibility(view.INVISIBLE);//隐藏WebView窗口
                    /* 关闭socket */
                    MyClient.Close_All();
                    textView_State.setText("已断开");
                    Log.v("button_Disconnect", "已断开");
                } else {
                    textView_State.setText("请勿重复断开");
                    Log.v("button_Disconnect", "请勿重复断开");
                }
            }
        });

        editText_Host.setOnTouchListener(new View.OnTouchListener(){
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                if(motionEvent.getAction() == MotionEvent.ACTION_DOWN){
                    editText_Host.setCursorVisible(true);
                }
                return false;
            }
        });

        editText_Port.setOnTouchListener(new View.OnTouchListener(){
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                if(motionEvent.getAction() == MotionEvent.ACTION_DOWN){
                    editText_Port.setCursorVisible(true);
                }
                return false;
            }
        });

        /*******************
         *  下面都是控制按钮  *
         *******************/
        /* 站立模式按钮 */
        button_Mode_standing.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        if (button_Disconnect.getText().equals("断开")) {
                            Message message = new Message();
                            message.what = myHandler.Button_mode;
                            message.obj = 1;
                            myHandler.sendMessage(message);
                            MyClient.Send(Control_mode_standing+"\r\n");
                        }
                    }
                }).start();
            }
        });

        /* 遥控模式按钮 */
        button_Mode_telecontrol.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Joystick_send_left_flag = false;
                Joystick_send_right_flag = false;
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        if (button_Disconnect.getText().equals("断开")) {
                            Message message = new Message();
                            message.what = myHandler.Button_mode;
                            message.obj = 2;
                            myHandler.sendMessage(message);
                            MyClient.Send(Control_mode_telecontrol+"\r\n");
                        }
                    }
                }).start();
            }
        });

        /* 避障模式按钮 */
        button_Mode_obstacle.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        if (button_Disconnect.getText().equals("断开")) {
                            Message message = new Message();
                            message.what = myHandler.Button_mode;
                            message.obj = 3;
                            myHandler.sendMessage(message);
                            MyClient.Send(Control_mode_obstacle+"\r\n");
                        }
                    }
                }).start();
            }
        });

        /* 灯光开关 */
        button_light.setOnClickListener(new View.OnClickListener(){

            @Override
            public void onClick(View view) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        if (button_Disconnect.getText().equals("断开")) {
                            if(button_light.getText().equals("开灯")){
                                Message message = new Message();
                                message.what = myHandler.Button_light;
                                message.obj = true;
                                myHandler.sendMessage(message);
                                MyClient.Send(Control_light_on+"\r\n");
                            }
                            else if(button_light.getText().equals("关灯")){
                                Message message = new Message();
                                message.what = myHandler.Button_light;
                                message.obj = false;
                                myHandler.sendMessage(message);
                                MyClient.Send(Control_light_off+"\r\n");
                            }
                        }
                    }
                }).start();
            }
        });

        /* 舵机摇杆 */
        moveButton_left.setOnTouchListener(new View.OnTouchListener(){
            @Override
            public boolean onTouch(View view, MotionEvent event) {

                int x = (int) event.getRawX();
                int y = (int) event.getRawY();
                switch (event.getAction()){
                    case MotionEvent.ACTION_DOWN:{
                        moveButton_left.lastX = x;
                        moveButton_left.lastY = y;
                        break;
                    }
                    case MotionEvent.ACTION_MOVE:{
                        double real_X= moveButton_left.getTranslationX()+(x - moveButton_left.lastX);
                        double real_Y= moveButton_left.getTranslationY()+(y - moveButton_left.lastY);
                        moveButton_left.Trans_Draw(real_X,real_Y);
                        break;
                    }
                    case MotionEvent.ACTION_UP:{
                        moveButton_left.Draw_x = 0;
                        moveButton_left.Draw_y = 0;
                        break;
                    }
                    default:break;
                }
                Log.v(":Draw_x",moveButton_left.ID+":"+moveButton_left.Draw_x);
                Log.v(":Draw_y",moveButton_left.ID+":"+moveButton_left.Draw_y);
                moveButton_left.setTranslationX((float) moveButton_left.Draw_x);
                moveButton_left.setTranslationY((float) moveButton_left.Draw_y);
                String buf = moveButton_left.Move_Button_steering_value(moveButton_left.Draw_x,moveButton_left.Draw_y);
                if(button_Disconnect.getText().equals("断开") && button_Mode_telecontrol.getCurrentTextColor() == Color.rgb(0,255,0)) {
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            MyClient.Send(buf + "\r\n");
                        }
                    }).start();
                }
                moveButton_left.lastX = x;
                moveButton_left.lastY = y;
                moveButton_left.invalidate();
                return true;
            }
        });

        /* 电机摇杆 */
        moveButton_right.setOnTouchListener(new View.OnTouchListener(){
            @Override
            public boolean onTouch(View view, MotionEvent event) {
                int x = (int) event.getRawX();
                int y = (int) event.getRawY();
                switch (event.getAction()){
                    case MotionEvent.ACTION_DOWN:{
                        moveButton_right.lastX = x;
                        moveButton_right.lastY = y;
                        break;
                    }
                    case MotionEvent.ACTION_MOVE:{
                        double real_X= moveButton_right.getTranslationX()+(x - moveButton_right.lastX);
                        double real_Y= moveButton_right.getTranslationY()+(y - moveButton_right.lastY);
                        moveButton_right.Trans_Draw(real_X,real_Y);
                        break;
                    }
                    case MotionEvent.ACTION_UP:{
                        moveButton_right.Draw_x = 0;
                        moveButton_right.Draw_y = 0;
                        break;
                    }
                    default:break;
                }
                Log.v(":Draw_x",moveButton_right.ID+":"+moveButton_right.Draw_x);
                Log.v(":Draw_y",moveButton_right.ID+":"+moveButton_right.Draw_y);
                moveButton_right.setTranslationX((float) moveButton_right.Draw_x);
                moveButton_right.setTranslationY((float) moveButton_right.Draw_y);
                String buf = moveButton_right.Move_Button_motor_value(moveButton_right.Draw_x,moveButton_right.Draw_y);
                if(button_Disconnect.getText().equals("断开") && button_Mode_telecontrol.getCurrentTextColor() == Color.rgb(0,255,0)){
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            MyClient.Send(buf+"\r\n");
                        }
                    }).start();
                }
                moveButton_right.lastX = x;
                moveButton_right.lastY = y;
                moveButton_right.invalidate();
                return true;
            }
        });
    }



    /* 下面是硬件手柄 */
    /* 只保留两位小数 */
    private float trans_float_2f(float value){
        return (float)((int)(value*100))/100;
    }

    /* 手柄检测 */
    private void updateGameControllerCount(){
        ArrayList<Integer> gameControllerIds = getGameControllerIds();
        if (gameControllerIds.size() == 0) {
            textView_Controller_State.setText("手柄未连接!");
        } else {
            textView_Controller_State.setText("手柄已连接!");
        }
    }

    /* 手柄检测并将设备放入数组 */
    public ArrayList<Integer> getGameControllerIds(){
        ArrayList<Integer> gameControllerDeviceIds = new ArrayList<Integer>();
        int[] deviceIds = InputDevice.getDeviceIds();
        for(int deviceId : deviceIds){
            InputDevice dev = InputDevice.getDevice(deviceId);
            int sources = dev.getSources();
            if(((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) || ((sources & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK)){
                if (!gameControllerDeviceIds.contains(deviceId)) {
                    gameControllerDeviceIds.add(deviceId);
                }
            }
        }
        return gameControllerDeviceIds;
    }

    public static boolean isDpadDevice(InputEvent event){
        if((event.getSource() & InputDevice.SOURCE_DPAD) != InputDevice.SOURCE_DPAD){
            return true;
        }
        else {
            return false;
        }
    }

    public int getDirectionPressed(MotionEvent event){
        if(!isDpadDevice(event)){
            return -1;
        }
//        MotionEvent motionEvent = (MotionEvent) event;
        float xaxis = event.getAxisValue(MotionEvent.AXIS_HAT_X);
        float yaxis = event.getAxisValue(MotionEvent.AXIS_HAT_Y);
        Log.v("xaxis",""+xaxis);
        Log.v("yaxis",""+yaxis);
        // Check if the AXIS_HAT_X value is -1 or 1, and set the D-pad
        // LEFT and RIGHT direction accordingly.
        if (Float.compare(xaxis, -1.0f) == 0) {
            directionPressed = KeyEvent.KEYCODE_DPAD_LEFT;
            dpadAction = KeyEvent.ACTION_DOWN;
        } else if (Float.compare(xaxis, 1.0f) == 0) {
            directionPressed = KeyEvent.KEYCODE_DPAD_RIGHT;
            dpadAction = KeyEvent.ACTION_DOWN;
        }
        // Check if the AXIS_HAT_Y value is -1 or 1, and set the D-pad
        // UP and DOWN direction accordingly.
        else if (Float.compare(yaxis, -1.0f) == 0) {
            directionPressed = KeyEvent.KEYCODE_DPAD_UP;
            dpadAction = KeyEvent.ACTION_DOWN;
        } else if (Float.compare(yaxis, 1.0f) == 0) {
            directionPressed = KeyEvent.KEYCODE_DPAD_DOWN;
            dpadAction = KeyEvent.ACTION_DOWN;
        } else {
            dpadAction = KeyEvent.ACTION_UP;
        }
        return directionPressed;
    }

    @Override
    public boolean dispatchGenericMotionEvent(MotionEvent ev) {
        Log.d(TAG, "dispatchGenericMotionEvent");
        if(isDpadDevice(ev)){
            int press = getDirectionPressed(ev);
            String keyName = "";
            switch (press) {
                case KeyEvent.KEYCODE_DPAD_LEFT:
                    keyName = "DPAD_LEFT";
                    break;
                case KeyEvent.KEYCODE_DPAD_RIGHT:
                    keyName = "DPAD_RIGHT";
                    break;
                case KeyEvent.KEYCODE_DPAD_UP:
                    keyName = "DPAD_UP";
                    break;
                case KeyEvent.KEYCODE_DPAD_DOWN:
                    keyName = "DPAD_DOWN";
                    break;
                default:
                    break;
            }
            if (!keyName.isEmpty()) {
                //textView_State.setText(String.format(Locale.getDefault(), "%s:%s", keyName, dpadAction == 0 ? "down" : "up"));
                Log.d(TAG, "key code:" + press + ";action:" + dpadAction);
                if (dpadAction == KeyEvent.ACTION_UP) {
                    directionPressed = -1;
                    dpadAction = -1;
                }
                return true;
            }
        }
        if ((ev.getSource() & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK && ev.getAction() == MotionEvent.ACTION_MOVE) {
            String joystick = "";
            leftJoystickX = trans_float_2f(ev.getAxisValue(MotionEvent.AXIS_X));
            if (Float.compare(leftJoystickX, mPreviousLeftJoystickX) != 0) {
                joystick += "leftJoystickX:" + leftJoystickX + ";";
            }
            mPreviousLeftJoystickX = leftJoystickX;

            leftJoystickY = trans_float_2f(ev.getAxisValue(MotionEvent.AXIS_Y));
            if (Float.compare(leftJoystickY, mPreviousLeftJoystickY) != 0) {
                joystick += "leftJoystickY:" + leftJoystickY + ";";
            }
            mPreviousLeftJoystickY = leftJoystickY;

            rightJoystickX = trans_float_2f(ev.getAxisValue(MotionEvent.AXIS_Z));
            if (Float.compare(rightJoystickX, mPreviousRightJoystickX) != 0) {
                joystick += "rightJoystickX:" + rightJoystickX + ";";
            }
            mPreviousRightJoystickX = rightJoystickX;

            rightJoystickY = trans_float_2f(ev.getAxisValue(MotionEvent.AXIS_RZ));
            if (Float.compare(rightJoystickY, mPreviousRightJoystickY) != 0) {
                joystick += "rightJoystickY:" + rightJoystickY + ";";
            }
            mPreviousRightJoystickY = rightJoystickY;

            //textView_State.setText(joystick);
            Log.d(TAG, "DeviceId:" + ev.getDeviceId() + ";AXIS_LX:" + leftJoystickX + ";AXIS_LY:" + leftJoystickY + ";AXIS_RX:" + rightJoystickX + ";AXIS_RY:" + rightJoystickY);
            moveButton_left.Trans_Draw(leftJoystickX*moveButton_left.Max_Distance,leftJoystickY*moveButton_left.Max_Distance);
            moveButton_left.setTranslationX((float)moveButton_left.Draw_x);
            moveButton_left.setTranslationY((float)moveButton_left.Draw_y);
            moveButton_left.invalidate();
            moveButton_right.Trans_Draw(rightJoystickX*moveButton_right.Max_Distance,rightJoystickY*moveButton_right.Max_Distance);
            moveButton_right.setTranslationX((float)moveButton_right.Draw_x);
            moveButton_right.setTranslationY((float)moveButton_right.Draw_y);
            moveButton_right.invalidate();
            return true;
        }
        return super.dispatchGenericMotionEvent(ev);
    }

    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        if ((event.getSource() & InputDevice.SOURCE_GAMEPAD)
                == InputDevice.SOURCE_GAMEPAD) {
            String keyName = "";
            switch (event.getKeyCode()) {
                case KeyEvent.KEYCODE_BUTTON_X:
                    keyName = "BUTTON_X";
                    break;
                case KeyEvent.KEYCODE_BUTTON_Y:
                    keyName = "BUTTON_Y";
                    break;
                case KeyEvent.KEYCODE_BUTTON_A:
                    keyName = "BUTTON_A";
                    break;
                case KeyEvent.KEYCODE_BUTTON_B:
                    keyName = "BUTTON_B";
                    break;
                case KeyEvent.KEYCODE_BUTTON_L1:
                    keyName = "BUTTON_L1";
                    break;
                case KeyEvent.KEYCODE_BUTTON_R1:
                    keyName = "BUTTON_R1";
                    break;
                case KeyEvent.KEYCODE_BUTTON_L2:
                    keyName = "BUTTON_L2";
                    break;
                case KeyEvent.KEYCODE_BUTTON_R2:
                    keyName = "BUTTON_R2";
                    break;
                case KeyEvent.KEYCODE_BUTTON_START:
                    keyName = "BUTTON_START";
                    break;
                case KeyEvent.KEYCODE_BUTTON_SELECT:
                    keyName = "BUTTON_SELECT";
                    break;
                default:
                    Log.d(TAG, "dispatchKeyEvent-other-KeyCode:" + event.getKeyCode());
                    break;
            }
            //textView_State.setText(String.format(Locale.getDefault(), "%s:%s", keyName, dpadAction == 0 ? "down" : "up"));
            Log.d(TAG, "key code:" + event.getKeyCode() + ";action:" + event.getAction());
            return true;
        }
        return super.dispatchKeyEvent(event);
    }

    @Override
    public void onInputDeviceAdded(int i) {
        Log.d(TAG, "onInputDeviceAdded:" + i);
        updateGameControllerCount();
    }

    @Override
    public void onInputDeviceRemoved(int i) {
        Log.d(TAG, "onInputDeviceRemoved:" + i);
        updateGameControllerCount();
    }

    @Override
    public void onInputDeviceChanged(int i) {
        Log.d(TAG, "onInputDeviceChanged:" + i);
        updateGameControllerCount();
    }

}

